package com.duan.laugh.msg.listener;

import com.duan.laugh.msg.api.constans.MsgConstants;
import com.duan.laugh.msg.api.pojo.DTO.MsgDTO;
import com.duan.laugh.msg.api.pojo.entity.MsgSend;
import com.duan.laugh.msg.api.pojo.entity.Remind;
import com.duan.laugh.msg.api.pojo.entity.Todo;
import com.duan.laugh.msg.service.IRemindService;
import com.duan.laugh.msg.service.ITodoService;
import com.duan.laugh.msg.service.MsgService;
import com.duan.laugh.upms.api.feign.UserService;
import com.duan.laugh.upms.api.pojo.entity.User;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;

import static com.duan.laugh.common.event.constants.EventConstant.*;
import static com.duan.laugh.msg.api.constans.MsgConstants.*;

/**
 * 队列消息监听
 *
 * @author duanjw
 */
@Component
@Slf4j
@AllArgsConstructor
public class MsgReceiveListener {

    private final MsgService msgService;
    @Autowired
    private ITodoService todoService;
    @Autowired
    private IRemindService remindService;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private UserService userService;

    /**
     * 监听msg队列消息
     *
     * @param msg
     */
    @RabbitListener(queues = MsgConstants.MQ_QUEUE_MSG)
    public void receive(MsgDTO msg) {
        log.info("消息中心接收到消息发送请求，参数：【{}】", msg);
        // 保存消息或代办
        this.saveTodoOrRemind(msg);
        List<MsgSend> msgSends = msg.getMsgSends();
        MsgSend msgSend = null;
        for (int i = 0, n = msgSends.size(); i < n; i++) {
            msgSend = msgSends.get(i);
            // 通知接受对象类型
            Integer receiveObject = msgSend.getReceiveObject();
            // 通知接受对象类型 - 用户
            if (RECEIVE_TYPE_USER.equals(receiveObject)) {
                // 给用户推送消息
                this.sendMsgTypeOfUser(msgSend);
            }
        }
        log.info("消息中心处理完毕");
    }

    /**
     * 监听站内队列消息
     *
     * @param msgSend
     */
    @RabbitListener(queues = MsgConstants.MQ_QUEUE_USER_MSG)
    public void receiveUserMsg(MsgSend msgSend) {
        log.info("监听到站内消息发送请求：【{}】", msgSend);
        msgService.sendMsgToUser(msgSend);
        log.info("给指定用户推送站内消息完毕");
    }

    /**
     * 通知接受对象类型 - 用户(给用户推送消息)
     *
     * @param msgSend
     */
    private void sendMsgTypeOfUser(MsgSend msgSend) {
        // 获取用户数据
        List<User> userInfo = this.getUserInfoByUserIds(msgSend.getReceiveObjectValue());
        // 事件消息类型
        Integer type = msgSend.getType();
        // 站内消息
        if (MSG_TYPE_MESSAGE.equals(type)) {
//                    amqpTemplate.convertAndSend(MQ_QUEUE_USER_MSG, msgSend);
            log.info("准备发送站内消息，参数：【{}】，发送时间为：【{}】", msgSend, msgSend.getSendTime());
            this.sendMsgByDelay(msgSend, MQ_EXCHANGE_USER_MSG_DELAY, MQ_QUEUE_USER_MSG_DELAY);
        }
        // 邮件
        else if (MSG_TYPE_EMAIL.equals(type)) {
            StringJoiner stringJoiner = new StringJoiner(",");
            for (User user : userInfo) {
                stringJoiner.add(user.getEmail());
            }
            msgSend.setReceiveObjectValue(stringJoiner.toString());
            log.info("准备发送邮件，参数：【{}】，发送时间为：【{}】", msgSend, msgSend.getSendTime());
            this.sendMsgByDelay(msgSend, MQ_EXCHANGE_EMAIL_DELAY, MQ_QUEUE_EMAIL_DELAY);
        }
        // 微信
        else if (MSG_TYPE_MP.equals(type)) {
            StringJoiner stringJoiner = new StringJoiner(",");
            for (User user : userInfo) {
                stringJoiner.add(user.getWxOpenid());
            }
            msgSend.setReceiveObjectValue(stringJoiner.toString());
            log.info("准备发送微信，参数：【{}】，发送时间为：【{}】", msgSend, msgSend.getSendTime());
            this.sendMsgByDelay(msgSend, MQ_EXCHANGE_MP_DELAY, MQ_QUEUE_MP_DELAY);
        }
        // 短信
        else if (MSG_TYPE_SMS.equals(type)) {
            StringJoiner stringJoiner = new StringJoiner(",");
            for (User user : userInfo) {
                stringJoiner.add(user.getPhone());
            }
            msgSend.setReceiveObjectValue(stringJoiner.toString());
            log.info("准备发送短信，参数：【{}】，发送时间为：【{}】", msgSend, msgSend.getSendTime());
            this.sendMsgByDelay(msgSend, MQ_EXCHANGE_SMS_DELAY, MQ_QUEUE_SMS_DELAY);
        }
    }

    /**
     * 调用 upms 获取用户信息
     *
     * @param userIds
     * @return
     */
    private List<User> getUserInfoByUserIds(String userIds) {
        Map<String, String> params = new HashMap<>(1);
        params.put("ids", userIds);
        return userService.selectInfoByUserIds(params).getData();
    }

    /**
     * 保存消息或者代办
     *
     * @param msg
     */
    private void saveTodoOrRemind(MsgDTO msg) {
        Integer handling = msg.getHandling();
        // 人为处理 - 代办
        if (HANDLING_TYPE_PERSON.equals(handling)) {
            Todo todo = new Todo();
            BeanUtils.copyProperties(msg, todo);
            todo.setStatus(STATUS_TODO_UNDO);
            todoService.save(todo);
            log.info("添加代办成功，参数：【{}】", todo);
        } else {
            // 消息
            Remind remind = new Remind();
            BeanUtils.copyProperties(msg, remind);
            remind.setStatus(STATUS_UNREAD);
            remindService.save(remind);
            log.info("添加消息成功，参数：【{}】", remind);
        }
    }

    /**
     * 延迟发送
     *
     * @param msgSend
     * @param mqExchangeQueueDelay
     * @param mqQueueDelay
     */
    private void sendMsgByDelay(MsgSend msgSend, String mqExchangeQueueDelay, String mqQueueDelay) {
        LocalDateTime sendTime = msgSend.getSendTime();
        LocalDateTime now = LocalDateTime.now();
        long delayMillis = Duration.between(now, sendTime).toMillis();
        log.info("延迟发送的时间差为(毫秒)：【{}】", delayMillis);
        amqpTemplate.convertAndSend(mqExchangeQueueDelay, mqQueueDelay, msgSend, message -> {
            // 发送时间 - 现在时间 = 延迟时间（单位毫秒）
            message.getMessageProperties().setHeader("x-delay", delayMillis);
            return message;
        });
    }
}
